package cn.iocoder.yudao.module.trade.service.fruitcard;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuFruitCardSelectDTO;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.fruitcard.vo.*;
import cn.iocoder.yudao.module.trade.convert.fruitcard.FruitCardConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.fruitcard.FruitCardDetailMapper;
import cn.iocoder.yudao.module.trade.dal.dataobject.fruitcard.FruitCardMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.fruitcard.FruitCardDO;
import cn.iocoder.yudao.module.trade.dal.mysql.fruitcard.FruitCardDetailDO;
import cn.iocoder.yudao.module.trade.enums.fruitcard.ErrorCodeConstants;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.framework.common.pojo.PageResult;


import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;

/**
 * 水果卡 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class FruitCardServiceImpl implements FruitCardService {

    @Resource
    private FruitCardMapper cardMapper;
    @Resource
    private FruitCardDetailMapper cardDetailMapper;

    @Resource
    private DictDataApi dataApi;

    @Resource
    private ProductSpuApi productSpuApi;

    @Override
    public Long createCard(FruitCardCreateReqVO createReqVO) {
        // 插入
        FruitCardDO card = FruitCardConvert.INSTANCE.convert(createReqVO);
        cardMapper.insert(card);
        // 返回
        return card.getId();
    }

    @Override
    public void updateCard(FruitCardUpdateReqVO updateReqVO) {
        // 校验存在
        validateCardExists(updateReqVO.getId());
        validateCardDetailExists(updateReqVO.getId());
        // 更新
        FruitCardDO updateObj = FruitCardConvert.INSTANCE.convert(updateReqVO);
        cardMapper.updateById(updateObj);
    }

    @Override
    public void deleteCard(Long id) {
        // 校验存在
        validateCardExists(id);
        validateCardDetailExists(id);
        // 删除
        cardMapper.deleteById(id);
    }

    private void validateCardDetailExists(Long id) {
        Long count = cardDetailMapper.selectCount(
                Wrappers
                        .<FruitCardDetailDO>lambdaQuery()
                        .eq(FruitCardDetailDO::getFruitCardId, id)
        );

        if (!ObjectUtils.isEmpty(count) && count > 0) {
            throw exception(CARD_DETAIL_EXISTS);
        }
    }

    private void validateCardExists(Long id) {
        if (cardMapper.selectById(id) == null) {
            throw exception(CARD_NOT_EXISTS);
        }
    }

    @Override
    public FruitCardDO getCard(Long id) {
        return cardMapper.selectById(id);
    }

    @Override
    public List<FruitCardDO> getCardList(Collection<Long> ids) {
        return cardMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<FruitCardRespVO> getCardPage(FruitCardPageReqVO pageReqVO) {

        PageResult<FruitCardDO> fruitCardDOPageResult = cardMapper.selectPage(pageReqVO);
        PageResult<FruitCardRespVO> voPageResult = FruitCardConvert.INSTANCE.convertPage(fruitCardDOPageResult);

        if (ObjectUtils.isEmpty(fruitCardDOPageResult)
                || CollectionUtils.isEmpty(fruitCardDOPageResult.getList())) {
            return voPageResult;
        }

        List<ProductSpuFruitCardSelectDTO> fruitCardSelectDTOS =
                productSpuApi.getSpuFruitCardSelectList(fruitCardDOPageResult.getList().stream().map(FruitCardDO::getFruitType).map(Long::valueOf).collect(Collectors.toList()));

        List<Long> fruitCardIds =
                fruitCardDOPageResult.getList().stream().map(FruitCardDO::getId).collect(Collectors.toList());

        List<DictDataRespDTO> datas = dataApi.getDictDataList("fruit_card_type");

        voPageResult.getList().forEach(f -> {

            datas.stream().filter(d -> d.getValue().equals(f.getCardType())).findFirst().ifPresent(d -> {
                f.setCardTypeLabel(d.getLabel());
            });

            fruitCardSelectDTOS. stream().filter(d -> d.getId().equals(Long.valueOf(f.getFruitType()))).findFirst().ifPresent(d -> {
                f.setFruitTypeName(d.getName());
            });


            f.setTotalCount(0);
            f.setActiveCount(0);

            if (!ObjectUtils.isEmpty(f.getPrice()) && f.getPrice() > 0) {
                f.setPriceYuan(String.valueOf(f.getPrice() / 100.0));
            }


        });

        List<FruitCardDetailSummaryVO> vos = cardDetailMapper.detailSummaryByFruitCardIds(fruitCardIds);
        if (ObjectUtils.isEmpty(vos)) {
            return voPageResult;
        }


        Map<Long, List<FruitCardDetailSummaryVO>> collect = vos.stream().collect(
                Collectors.groupingBy(FruitCardDetailSummaryVO::getFruitCardId));

        voPageResult.getList().forEach(f -> {

            if (collect.containsKey(f.getId())) {
                List<FruitCardDetailSummaryVO> fruitCardDetailSummaryVOS = collect.get(f.getId());
                f.setTotalCount(fruitCardDetailSummaryVOS.stream().mapToInt(FruitCardDetailSummaryVO::getNums).sum());
                Optional<FruitCardDetailSummaryVO> first = fruitCardDetailSummaryVOS.stream().filter(v -> v.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())).findFirst();
                if(first.isPresent()){
                    f.setActiveCount(
                            first.get().getNums()
                    );
                }

            }

        });

        return voPageResult;
    }

    @Override
    public List<FruitCardDO> getCardList(FruitCardExportReqVO exportReqVO) {
        return cardMapper.selectList(exportReqVO);
    }

    @Override
    public void initBatch(FruitCardInitBatchReqVO vo) {
        validateCardExists(vo.getId());
        FruitCardDO fruitCardDO = cardMapper.selectById(vo.getId());
        if (fruitCardDO.getStatus().equals(Boolean.TRUE)) {
            throw exception(CANNOT_BATCH_INIT);
        }
        List<FruitCardDetailDO> fruitCardDetailDOS = cardDetailMapper.selectList();
        Set<String> cardNos = new HashSet<>();
        if(CollectionUtils.isEmpty(fruitCardDetailDOS)){
             cardNos =
                    fruitCardDetailDOS.stream().map(FruitCardDetailDO::getCardNo).collect(Collectors.toSet());
        }

        List<FruitCardDetailDO> list = new ArrayList<>();
        for (int i = 0; i < vo.getQuantity(); i++) {
            FruitCardDetailDO fruitCardDetailDO = new FruitCardDetailDO();
            fruitCardDetailDO.setFruitCardId(vo.getId());
            fruitCardDetailDO.setCardPwd(RandomUtil.randomString(12));
            fruitCardDetailDO.setCardNo(IdUtil.getSnowflakeNextIdStr());
            if(cardNos.contains(fruitCardDetailDO.getCardNo())){
                i--;
            }else{
                cardNos.add(fruitCardDetailDO.getCardNo());
                list.add(fruitCardDetailDO);
            }

        }
        cardDetailMapper.insertBatch(list);
    }

    @Override
    public void updateCardStatus(FruitCardUpdateStatusReqVO updateReqVO) {
        validateCardExists(updateReqVO.getId());
        validateCardDetailExists(updateReqVO.getId());
        cardMapper.update(null,Wrappers.<FruitCardDO>lambdaUpdate().eq(FruitCardDO::getId,updateReqVO.getId()).set(FruitCardDO::getStatus,updateReqVO.getStatus()));
    }


}
